import { Directive, DirectiveBinding } from 'vue';

const textEllipsis: Directive = (el: HTMLElement, binding: DirectiveBinding<string>): void => {
    const { value = '', arg } = binding;
    const maxLines = Number.parseInt(arg ?? '1', 10);
    // 单行直接用css控制
    if (maxLines === 1) {
        overflowSingleRow(el, value);
        return;
    }
    overflowHidden(el, maxLines, value);
    initListener(el, maxLines, value);
};

/**
 * 设置单行省略
 * @param el 文本容器
 * @param value 文本值
 */
function overflowSingleRow(el: HTMLElement, value: string): void {
    el.style.overflow = 'hidden';
    el.style.whiteSpace = 'nowrap';
    el.style.textOverflow = 'ellipsis';
    el.style.wordWrap = 'normal';
    el.style.wordBreak = 'break-all';
    el.innerText = value;
}

/**
 * 监听窗口信息变化
 * @param el 文本容器
 * @param maxLines 最大行数
 * @param value 文本值
 */
function initListener(el: HTMLElement, maxLines: number, value: string): void {
    const listenOverflow = () => {
        if (el) {
            overflowHidden(el, maxLines, value);
        }
    };
    window.addEventListener('resize', listenOverflow);
    window.addEventListener('beforeunload', () => {
        window.removeEventListener('resize', listenOverflow);
    });
}

/**
 * 多行省略
 * @param el 文本容器
 * @param maxLines 最大行数
 * @param value 文本值
 */
function overflowHidden(el: HTMLElement, maxLines: number, value: string): void {
    const style: CSSStyleDeclaration = window.getComputedStyle(el);
    const availableWidth = getAvailableWidth();
    if (!availableWidth) {
        return;
    }
    el.innerText = getAvailableText(availableWidth);

    /**
     * 获取可用文本
     */
    function getAvailableText(availableWidth: number): string {
        const fontSize = parseInt(style.fontSize, 10);
        const rowCount = Math.floor(availableWidth / fontSize);
        if (value.length <= maxLines * rowCount) {
            return value;
        } else {
            return value.substring(0, maxLines * rowCount - 3) + '...';
        }
    }

    /**
     * 获取可用宽度
     */
    function getAvailableWidth(): number | undefined {
        const width = parseInt(style['width'], 10);
        if (Number.isNaN(width)) {
            return;
        }
        const paddingLeft = parseInt(style.paddingLeft, 10);
        const paddingRight = parseInt(style.paddingRight, 10);
        return (
            width -
            (isNaN(paddingLeft) ? 0 : paddingLeft) -
            (isNaN(paddingRight) ? 0 : paddingRight)
        );
    }
}

export default textEllipsis;
